home *** CD-ROM | disk | FTP | other *** search
/ BBS in a Box 7 / BBS in a Box - Macintosh - Volume VII (BBS in a Box) (January 1993).iso / Files / Prog / D-G / Floating Windows.cpt / Floating Windows / Floating.p next >
Encoding:
Text File  |  1991-08-21  |  16.0 KB  |  548 lines  |  [TEXT/PJMM]

  1. UNIT Floating;
  2.  
  3. INTERFACE
  4.  
  5. VAR
  6.     bottomFloat, topFloat, topWindow: WindowPtr;
  7.     curActivate, curDeactive: WindowPtr;
  8.  
  9.     drawRgn, windowRgn, dragRgn: RgnHandle;
  10.     wPort: GrafPtr;
  11.     dragRect: Rect;
  12.  
  13.  
  14. PROCEDURE InitFloat;
  15. PROCEDURE UpdateTopWindow;
  16. PROCEDURE UpdateFloats;
  17. FUNCTION NewFloatingWindow (ResID: Integer; wStorage: Ptr): WindowPtr;
  18. PROCEDURE MakeFloating (whichWindow: WindowPtr);
  19. FUNCTION IsFloating (whichWindow: WindowPtr): boolean;
  20. PROCEDURE CloseTheWindow (whichWindow: windowPtr);
  21. PROCEDURE DisposeTheWindow (whichWindow: WindowPtr);
  22. PROCEDURE ShowTheWindow (whichWindow: WindowPtr);
  23. PROCEDURE HideTheWindow (whichWindow: WindowPtr);
  24. PROCEDURE ShowFloats;
  25. PROCEDURE HideFloats;
  26. FUNCTION CurrentWindow: WindowPtr;
  27. PROCEDURE SelectTheWindow (whichWindow: WindowPtr);
  28. PROCEDURE DragTheWindow (whichWindow: WindowPtr; theEvent: EventRecord);
  29. PROCEDURE CalcWindowVis (whichWindow: WindowPeek);
  30. PROCEDURE GlobalRgn (VAR changeRgn: RgnHandle);
  31. PROCEDURE LocalRgn (VAR changeRgn: RgnHandle);
  32.  
  33.  
  34. IMPLEMENTATION
  35.  
  36.  
  37. PROCEDURE InitFloat;
  38. { Initialize all of the internal variables }
  39.     BEGIN
  40.         drawRgn := NewRgn;
  41.         windowRgn := NewRgn;
  42.         dragRgn := NewRgn;
  43.         wPort := GrafPtr(NewPtr(SizeOf(GrafPort)));
  44.         OpenPort(wPort);
  45.  
  46.         topFloat := NIL;
  47.         bottomFloat := NIL;
  48.         topWindow := NIL;
  49.  
  50.         dragRect := screenBits.bounds;
  51.         InsetRect(dragRect, 4, 4);
  52.     END;
  53.  
  54.  
  55. PROCEDURE UpdateTopWindow;
  56.     BEGIN
  57.         IF bottomFloat <> NIL THEN
  58.             topWindow := WindowPtr(WindowPeek(bottomFloat)^.nextWindow)
  59.         ELSE
  60.             topWindow := FrontWindow;
  61.     END;
  62.  
  63.  
  64. PROCEDURE UpdateFloats;
  65.     VAR
  66.         theWindow: WindowPeek;
  67.  
  68.     BEGIN
  69.         topFloat := NIL;
  70.         bottomFloat := NIL;
  71.         theWindow := WindowPeek(FrontWindow);        { Start with the front window }
  72.         IF theWindow <> NIL THEN
  73.             IF IsFloating(WindowPtr(theWindow)) THEN    { Is it a floating window? }
  74.             BEGIN
  75.                 topFloat := WindowPtr(theWindow);    { Yep, let's start figuring out our list starting with that one }
  76.                 WHILE IsFloating(WindowPtr(theWindow)) DO
  77.                 BEGIN            { Continue updating our bottom pointer until we have found the last window }
  78.                     bottomFloat := WindowPtr(theWindow);
  79.                     theWindow := theWindow^.nextWindow;
  80.                     IF theWindow = NIL THEN
  81.                         Exit(UpdateFloats);
  82.                 END;
  83.             END;
  84.     END;
  85.  
  86.  
  87. PROCEDURE MakeFloating (whichWindow: WindowPtr);
  88.     BEGIN
  89.         WindowPeek(whichWindow)^.windowKind := 317;        { Mark it as a floating window }
  90.         BringToFront(whichWindow);    { Floating window must be in front }
  91.     END;
  92.  
  93.  
  94. FUNCTION NewFloatingWindow (ResID: Integer; wStorage: Ptr): WindowPtr;
  95.     VAR
  96.         theWindow: WindowPtr;
  97.  
  98.     BEGIN
  99.         theWindow := GetNewWindow(ResID, wStorage, NIL);
  100.  
  101.         BringToFront(theWindow);        { Floating window must be in front }
  102.         ShowHide(theWindow, true);        { Make sure it is visible }
  103.         IF topFloat = NIL THEN            { If topFloat is NIL then this is the }
  104.             bottomFloat := theWindow;    { the first floating window to be }
  105.                                         { made. Since it is the first, it must }
  106.                                         { also be the last }
  107.         topFloat := theWindow;            { Mark it is as the top floating window }
  108.         MakeFloating(theWindow);        { And mark it as a floating window }
  109.         NewFloatingWindow := theWindow;    { Return reference to theWindow }
  110.     END;
  111.  
  112.  
  113.  
  114. FUNCTION IsFloating (whichWindow: WindowPtr): Boolean;
  115.     BEGIN
  116.         IsFloating := WindowPeek(whichWindow)^.windowKind = 317;
  117.     END;
  118.  
  119.  
  120. PROCEDURE CloseTheWindow (whichWindow: WindowPtr);
  121.     VAR
  122.         theWindow: WindowPeek;
  123.  
  124.     BEGIN
  125.         CloseWindow(whichWindow);
  126.  
  127.     { Calculate the next window to hilite. Start with the next window }
  128.     { behind the one you are closing. Continue until you find the first }
  129.     { visable one. }
  130.  
  131.         theWindow := WindowPeek(whichWindow)^.nextWindow;
  132.  
  133.         whichWindow := NIL;    { get rid of the window! }
  134.  
  135.         IF theWindow <> NIL THEN
  136.         BEGIN
  137.             WHILE NOT theWindow^.visible DO
  138.             BEGIN
  139.                 theWindow := theWindow^.nextWindow;
  140.                 IF theWindow = NIL THEN
  141.                     Exit(CloseTheWindow);
  142.             END
  143.         END;
  144.  
  145.     { If we got a window (other than 0L) then Hilite it and tell the }
  146.     {  toolbox to activate that window }
  147.         IF theWindow <> NIL THEN
  148.         BEGIN
  149.             HiliteWindow(WindowPtr(theWindow), true);
  150.             CurActivate := WindowPtr(theWindow);
  151.         { Since one of the windows that was killed could have been a floating }
  152.         { window. We rebuild that list starting with the frontmost window }
  153.         { and working the way through the list until we find the first }
  154.         { nonfloating window which marks the end of the floats. }
  155.  
  156.             UpdateFloats;
  157.         END
  158.         ELSE        { We have no windows left so hide our floats }
  159.             HideFloats;
  160.         UpdateTopWindow;
  161.     END;
  162.  
  163.  
  164. PROCEDURE DisposeTheWindow (whichWindow: WindowPtr);
  165.     VAR
  166.         theWindow: WindowPeek;
  167.     BEGIN
  168.         DisposeWindow(whichWindow);
  169.                             { Calculate the next window to hilite. Start with the next window }
  170.                             { behind the one you are closing. Continue until you find the first }
  171.                             { visible one. }
  172.         theWindow := WindowPeek(whichWindow)^.nextWindow;
  173.         IF theWindow <> NIL THEN
  174.             WHILE NOT theWindow^.visible DO
  175.                 theWindow := theWindow^.nextWindow;
  176.  
  177.         IF theWindow = NIL THEN
  178.             exit(DisposeTheWindow);
  179.  
  180.         { If we got a window (other than 0L) then Hilite it and tell the toolbox to activate it }
  181.         IF theWindow <> NIL THEN
  182.         BEGIN
  183.             HiliteWindow(WindowPtr(theWindow), true);
  184.             CurActivate := WindowPtr(theWindow);    { Since one of the windows that was killed }
  185.                                                     { could have been a floating window. We }
  186.                                                     { rebuild that list starting with the }
  187.                                                     { frontmost window and working the way through }
  188.                                                     { the list. }
  189.         END
  190.         ELSE        { We have no windows left so hide our floats }
  191.         BEGIN
  192.             HideFloats;
  193.             UpdateTopWindow;
  194.         END;
  195.     END;
  196.  
  197.  
  198. PROCEDURE HideTheWindow (whichWindow: WindowPtr);
  199.  
  200.     VAR
  201.         theWindow: WindowPeek;
  202.  
  203.     BEGIN
  204.         HideWindow(whichWindow);
  205.         { Start with the next window behind the one we are hiding.}
  206.         { Continue searching until we find a visible one. }
  207.         theWindow := WindowPeek(whichWindow)^.nextWindow;
  208.         WHILE NOT theWindow^.visible DO
  209.             theWindow := theWindow^.nextWindow;
  210.         IF theWindow = NIL THEN
  211.             exit(HideTheWindow);
  212.  
  213.         IF theWindow <> NIL THEN    { If we found a window, Hilite it }
  214.         BEGIN
  215.             HiliteWindow(WindowPtr(theWindow), true);
  216.             UpdateFloats;
  217.         END;
  218.     END;
  219.  
  220.  
  221. PROCEDURE ShowFloats;
  222.     VAR
  223.         theWindow: WindowPeek;
  224.     BEGIN
  225.         IF topFloat <> NIL THEN                    { Do we have floating windows? }
  226.             theWindow := WindowPeek(topFloat);    { Start with the top one }
  227.  
  228.         WHILE theWindow <> WindowPeek(bottomFloat)^.nextWindow DO
  229.         BEGIN
  230.                                             { Contine until we reach the last floating window }
  231.                                             { Show the window and move on to the next }
  232.             ShowHide(WindowPtr(theWindow), TRUE);
  233.             theWindow := theWindow^.nextWindow;
  234.         END;
  235.         IF theWindow = NIL THEN
  236.             exit(ShowFloats);
  237.     END;
  238.  
  239.  
  240. PROCEDURE HideFloats;
  241.     VAR
  242.         theWindow: WindowPeek;
  243.     BEGIN
  244.         IF topFloat <> NIL THEN { Do we have floating windows? }
  245.             theWindow := WindowPeek(topFloat);    { Start with the top one }
  246.         WHILE theWindow <> WindowPeek(bottomFloat)^.nextWindow DO
  247.         BEGIN
  248.                                                 { Contine until we reach the }
  249.                                                 { last floating window }
  250.                                                 { Hide the window and move }
  251.                                                 { on to the next }
  252.             ShowHide(WindowPtr(theWindow), false);
  253.             theWindow := theWindow^.nextWindow;
  254.         END;
  255.         IF theWindow = NIL THEN
  256.             exit(HideFloats)
  257.     END;
  258.  
  259.  
  260. FUNCTION CurrentWindow: WindowPtr;
  261.     BEGIN
  262.         CurrentWindow := topWindow;
  263.     END;
  264.  
  265.  
  266. PROCEDURE SelectTheWindow (whichWindow: WindowPtr);
  267.     VAR
  268.         floating: Boolean;        { Is it a floating window }
  269.         bottomPeek: WindowPeek;        { Reference to bottom float }
  270.         theWindowPeek: WindowPeek;    { Generic reference to window }
  271.         lastTop: WindowPtr;        { The last top window }
  272.         beforePeek: WindowPeek;        { The location of where the the window will be moved }
  273.         savePort: GrafPtr;
  274.  
  275.     BEGIN
  276.         floating := IsFloating(whichWindow);        { Is it a floating window? }
  277.         IF floating THEN
  278.         BEGIN
  279.             IF whichWindow <> topFloat THEN
  280.             BEGIN    { If it is not the front floating window, bring it to the front }
  281.                 BringToFront(whichWindow);
  282.                 topFloat := whichWindow;
  283.  
  284.             { and find the last floating window }
  285.                 theWindowPeek := WindowPeek(whichWindow);
  286.                 WHILE IsFloating(WindowPtr(theWindowPeek)) DO
  287.                 BEGIN
  288.                     bottomFloat := WindowPtr(theWindowPeek);
  289.                     theWindowPeek := theWindowPeek^.nextWindow;
  290.                 END
  291.             END
  292.         END
  293.         ELSE
  294.         BEGIN
  295.             IF bottomFloat = NIL THEN        { if there are no other floating windows }
  296.             BEGIN                            { just bring it to the front. }
  297.                 IF whichWindow <> FrontWindow THEN
  298.                     SelectWindow(whichWindow);
  299.             END
  300.             ELSE
  301.             BEGIN
  302.                 bottomPeek := WindowPeek(bottomFloat);
  303.                 theWindowPeek := WindowPeek(whichWindow);
  304.  
  305.                 IF theWindowPeek <> bottomPeek^.nextWindow THEN
  306.                 BEGIN
  307.                 { It's not the top document window, now we find what that is }
  308.                     lastTop := WindowPtr(bottomPeek^.nextWindow);
  309.  
  310.                 { Create deactivate event for last active document window }
  311.                     CurDeactive := lastTop;
  312.                     HiliteWindow(lastTop, false);
  313.  
  314.                  { Now we rewrite the window list to change the location }
  315.                  { of the window. First we find the window that was before }
  316.                  { the window we want to move. We then set its nextWindow }
  317.                  { field to the window in front of the window we are moving. }
  318.                  { That then removes the window from the window list. }
  319.                  { Now we want to place it rigth after the bottommost }
  320.                  { floating window. To do that, we set the nextWindow }
  321.                  { field of the window we are moving to the window right }
  322.                  { after the bottommost floating window and set the nextWindow }
  323.                  { field of the bottommost floating window to the window }
  324.                  { we are moving. Confusing eh? }
  325.  
  326.                     beforePeek := bottomPeek^.nextWindow;
  327.                     WHILE beforePeek^.nextWindow <> theWindowPeek DO
  328.                         beforePeek := beforePeek^.nextWindow;
  329.                     beforePeek^.nextWindow := theWindowPeek^.nextWindow;
  330.  
  331.                     theWindowPeek^.nextWindow := bottomPeek^.nextWindow;
  332.                     bottomPeek^.nextWindow := theWindowPeek;
  333.  
  334.                 { Now we have to recalculate all the visible regions }
  335.                 { and redraw newly exposed areas }
  336.  
  337.                     GetPort(savePort);
  338.                     SetPort(whichWindow);
  339.  
  340.                 { We start with the visible region of our window but }
  341.                 {  unfortunately, it is in local coordinates of the }
  342.                 {  window so we convert it to global by using the GlobalRgn }
  343.                 {  procedure }
  344.  
  345.                     CopyRgn(whichWindow^.visRgn, drawRgn);
  346.                     GlobalRgn(drawRgn);
  347.  
  348.                 { We then subtract the visible region of the window }
  349.                 { from the windows structure region. This gives us }
  350.                 { the area which is being brought to the front }
  351.  
  352.                     DiffRgn(theWindowPeek^.strucRgn, drawRgn, drawRgn);
  353.  
  354.                 { Paint the area and hilite it to show it is now active }
  355.                     PaintOne(WindowPeek(whichWindow), drawRgn);
  356.                     HiliteWindow(whichWindow, true);
  357.  
  358.                 { PaintOne sets thePort to the Window Manager Port so }
  359.                 {  we must reset thePort to whichWindow. We then call }
  360.                 {  CalcWindowVis which will recalculate all the visible }
  361.                 {  regions }
  362.  
  363.                     SetPort(whichWindow);
  364.                     CalcWindowVis(theWindowPeek);
  365.  
  366.                 { Then invalidate the region so that it will update properly }
  367.                     InvalRgn(drawRgn);
  368.                     SetPort(savePort);
  369.  
  370.                 { And finally, generate another event to activate the new window }
  371.                     CurActivate := whichWindow;
  372.                 END
  373.             END
  374.         END;
  375.         IF NOT WindowPeek(whichWindow)^.visible THEN  { A little kludge }
  376.                                { has been added for floating window support }
  377.                                { which makes sure to make the window visible }
  378.                                { if it is hidden }
  379.             ShowHide(whichWindow, true);
  380.  
  381.         UpdateTopWindow;        { Rebuild our window list }
  382.     END;
  383.  
  384.  
  385.  
  386. PROCEDURE DragTheWindow (whichWindow: WindowPtr; theEvent: EventRecord);
  387.     VAR
  388.         savePort: GrafPtr;        { Saved graphics pointer }
  389.         thePoint: Point;            { Used to remember the original }
  390.                     { location of the window }
  391.         newLoc: LongInt;            { Window's new position }
  392.         hDelta, vDelta: Integer;    { How much to move the window }
  393.         theWindow: WindowPeek;
  394.  
  395.     BEGIN
  396.  
  397. { Since dragging a window automatically brings it to the front }
  398. { unless you are holding the command key down, this routine needs }
  399. { to be redone. Otherwise it would kill the floating window }
  400. { relationship. }
  401.  
  402. { If it's a floating window and not the front floating window and }
  403. { the command key is not down, bring it to the front before dragging }
  404.  
  405.         IF IsFloating(whichWindow) THEN
  406.         BEGIN
  407.             IF (whichWindow <> topFloat) & NOT (BAND(theEvent.modifiers, cmdKey) = cmdKey) THEN
  408.                 SelectTheWindow(whichWindow);
  409.         END
  410.     { if the window is not the front document window and the command }
  411.     { key is not down, select the window before dragging }
  412.  
  413.         ELSE IF topFloat = NIL THEN
  414.         BEGIN
  415.             IF (whichWindow <> FrontWindow) & NOT (BAND(theEvent.modifiers, cmdKey) = cmdKey) THEN
  416.             BEGIN
  417.                 SelectWindow(whichWindow);
  418.             END
  419.         END
  420.         ELSE IF (whichWindow <> WindowPtr(WindowPeek(bottomFloat)^.nextWindow)) & NOT (BAND(theEvent.modifiers, cmdKey) = cmdKey) THEN
  421.         BEGIN
  422.             SelectTheWindow(whichWindow);
  423.         END;
  424.  
  425.         IF NOT StillDown THEN
  426.             Exit(DragTheWindow);
  427.  
  428.         GetPort(savePort);
  429.         SetPort(whichWindow);
  430.  
  431.     { remember the top-left coordinate of the window }
  432.         thePoint := whichWindow^.portRect.topLeft;
  433.         LocalToGlobal(thePoint);
  434.  
  435.     { Copy the window's structure region to be used for dragging }
  436.         CopyRgn(WindowPeek(whichWindow)^.strucRgn, dragRgn);
  437.  
  438.     { Use our graphics port }
  439.         SetPort(wPort);
  440.  
  441.     { We must figure out the drag region for the window. }
  442.     { Start with the top window and work or way through the window }
  443.     { list altering our graphics port to the screen's visible region. }
  444.     { This effectively gives us a visible region of the screen minus }
  445.     { that of all windows above the window we are dragging }
  446.  
  447.         CopyRgn(GetGrayRgn, wPort^.visRgn);
  448.  
  449.         theWindow := WindowPeek(FrontWindow);
  450.         IF theWindow <> WindowPeek(whichWindow) THEN
  451.         BEGIN
  452.             DiffRgn(wPort^.visRgn, theWindow^.strucRgn, wPort^.visRgn);
  453.             WHILE theWindow <> WindowPeek(whichWindow) DO
  454.             BEGIN
  455.                 DiffRgn(wPort^.visRgn, theWindow^.strucRgn, wPort^.visRgn);
  456.                 theWindow := theWindow^.nextWindow;
  457.             END;
  458.         END;
  459.  
  460.     { drag the window }
  461.         newLoc := DragGrayRgn(dragRgn, theEvent.where, dragRect, dragRect, noConstraint, NIL);
  462.         IF newLoc <> $80008000 THEN
  463.         BEGIN
  464.             hDelta := LoWord(newLoc);
  465.             vDelta := HiWord(newLoc);
  466.             MoveWindow(whichWindow, hDelta + thePoint.h, vDelta + thePoint.v, false);
  467.         END;
  468.         SetPort(savePort);
  469.     END;
  470.  
  471.  
  472.  
  473. PROCEDURE CalcWindowVis (whichWindow: WindowPeek);
  474.     VAR
  475.         theWindow: WindowPeek;
  476.         savePort: GrafPtr;
  477.  
  478.     BEGIN
  479.         GetPort(savePort);
  480.  
  481.         { First we start with an empty region. From there we begin with }
  482.         { the front window which would be one of the floating windows }
  483.         { and add its structure region to windowRgn. We continue to add }
  484.         { in the regions until we reach whichWindow }
  485.  
  486.         SetEmptyRgn(windowRgn);
  487.         theWindow := WindowPeek(FrontWindow);
  488.         WHILE theWindow <> whichWindow DO
  489.         BEGIN
  490.             UnionRgn(windowRgn, theWindow^.strucRgn, windowRgn);
  491.             theWindow := theWindow^.nextWindow;
  492.         END;
  493.  
  494. { We now have all the regions of all the windows in front of whichWindow. }
  495. { To calculate the visible region of whichWindow, we copy its content region }
  496. { (which is in global coordinates) into the visRgn field. }
  497. { We then SUBTRACT the region we generated before from the visible region }
  498. { of the window. Finally, convert it into local coordinates for the toolbox }
  499.  
  500.         SetPort(WindowPtr(whichWindow));
  501.         CopyRgn(whichWindow^.contRgn, whichWindow^.port.visRgn);
  502.         DiffRgn(whichWindow^.port.visRgn, windowRgn, whichWindow^.port.visRgn);
  503.         LocalRgn(whichWindow^.port.visRgn);
  504.  
  505. { Now we have to calculate all the visible regions for all windows behind }
  506. { whichWindow. We just go through the same process again and again, }
  507. { but each time we add the window's structure region into windowRgn to subtract again. }
  508.  
  509.         theWindow := whichWindow;
  510.         WHILE theWindow^.nextWindow <> NIL DO
  511.         BEGIN
  512.             UnionRgn(windowRgn, theWindow^.strucRgn, windowRgn);
  513.             theWindow := theWindow^.nextWindow;
  514.             SetPort(WindowPtr(theWindow));
  515.             CopyRgn(theWindow^.contRgn, theWindow^.port.visRgn);
  516.             DiffRgn(theWindow^.port.visRgn, windowRgn, theWindow^.port.visRgn);
  517.             LocalRgn(theWindow^.port.visRgn)
  518.         END;
  519.         SetPort(savePort);
  520.     END;
  521.  
  522.  
  523. PROCEDURE GlobalRgn (VAR changeRgn: RgnHandle);
  524. { Converts a region into Global Coordinates }
  525.     VAR
  526.         theRect: Rect;
  527.     BEGIN
  528.         theRect := thePort^.portBits.bounds;
  529.         OffsetRgn(changeRgn, -theRect.left, -theRect.top);
  530.  
  531.     END;
  532.  
  533.  
  534. PROCEDURE LocalRgn (VAR changeRgn: RgnHandle);
  535.     { Converts a region into Global Coordinates }
  536.     VAR
  537.         theRect: Rect;
  538.  
  539.     BEGIN
  540.         theRect := thePort^.portBits.bounds;
  541.         OffsetRgn(changeRgn, theRect.left, theRect.top);
  542.     END;
  543.  
  544.  
  545. END.
  546.  
  547.  
  548.